package cn.org.wifit.imserver.boot;

import org.springframework.context.ApplicationContext;

import cn.org.wifit.imserver.im.handle.TCPServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 为客户端开启netty的UDP服务
 */
public class StartupNettyTCPBoot implements Runnable {
	/**
	 * TCP准备的事件环路
	 */
	private EventLoopGroup tcpBossGroup;
	
	/**
	 * TCP准备的事件环路
	 */
	private EventLoopGroup tcpWorkerGroup;
	
	/**
	 * TCP服务的启动器
	 */
	private ServerBootstrap tcpBootstrap;
	
	/**
	 * 启动状态：0，表示还没有启动完
	 * 1，表示启动正常完成
	 * 2，启动完成，但是发生异常
	 */
	private Integer bootState = 0;

	@Override
	public void run() {
		try {
			this.bootState = 0;
			this.tcpBootstrap = this.tcpBootstrap.group(this.tcpBossGroup, this.tcpWorkerGroup);
			this.tcpBootstrap = this.tcpBootstrap.channel(NioServerSocketChannel.class);
			/*
			 * 通道的过滤过程为：
			 * 输入过滤器ByteToStudent、
			 * 处理器NettyProtocBFHandler、
			 * 输出过滤器StudentToByte
			 * */
			this.tcpBootstrap = this.tcpBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					//申请新的处理器
					ApplicationContext ap = BootStartup.context;
					TCPServerHandler handler = (TCPServerHandler)ap.getBean("tcpServerHandler");
					ch.pipeline().addLast(handler); 
				} 
			});
			
			//设置信道的其他配置，阅读apidocs of ChannelOption获取更多设置的解释
			this.tcpBootstrap = this.tcpBootstrap.option(ChannelOption.SO_BACKLOG, 128);
			//设置信道的其他配置，阅读apidocs of ChannelOption获取更多设置的解释,注意，这里设置的是childOption
			this.tcpBootstrap = this.tcpBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
			
			// Bind and start to accept incoming connections.
			String tcpPort = BootStartup.LOCAL_Environment.get("-T");
			
            ChannelFuture f = this.tcpBootstrap.bind(Integer.parseInt(tcpPort)).sync();
            this.bootState = 1;
            synchronized (this) {
				this.notify();
			}
            Channel channel = f.channel();
            channel.closeFuture().sync();
		} catch(Exception e) {
			e.printStackTrace(System.out);
			this.bootState = 2;
			synchronized (this) {
				this.notify();
			}
		} finally {
			
		}
	}

	/**
	 * 该方法一旦被调用，调用者线程将会等待，直到TCP连接建立完成（无论建立成功，还是建立失败）
	 */
	public void sync() throws Exception {
		try {
			synchronized (this) {
				while(this.bootState == 0) {
					this.wait();
				}
			}
			
			//如果条件成立，则抛出错误信息
			if(this.bootState == 2) {
				throw new RuntimeException("启动TCP出现错误，请检查机器状态和配置项");
			}
		} catch(Exception e) {
			e.printStackTrace(System.out);
		}
	}
	
	public EventLoopGroup getTcpBossGroup() {
		return tcpBossGroup;
	}

	public void setTcpBossGroup(EventLoopGroup tcpBossGroup) {
		this.tcpBossGroup = tcpBossGroup;
	}

	public EventLoopGroup getTcpWorkerGroup() {
		return tcpWorkerGroup;
	}

	public void setTcpWorkerGroup(EventLoopGroup tcpWorkerGroup) {
		this.tcpWorkerGroup = tcpWorkerGroup;
	}

	public ServerBootstrap getTcpBootstrap() {
		return tcpBootstrap;
	}

	public void setTcpBootstrap(ServerBootstrap tcpBootstrap) {
		this.tcpBootstrap = tcpBootstrap;
	}
} 